package cn.com.zetatech.loader.common.service.impl;

import cn.com.zetatech.loader.common.constant.LoaderConstant;
import cn.com.zetatech.loader.common.enums.FileMoveTypeEnums;
import cn.com.zetatech.loader.common.enums.FileStateEnums;
import cn.com.zetatech.loader.common.ftp.ConnectionClient;
import cn.com.zetatech.loader.common.message.LogMessageProducer;
import cn.com.zetatech.loader.common.message.ResolverMessage;
import cn.com.zetatech.loader.common.service.ResolverResultService;
import cn.com.zetatech.loader.common.util.ConnectionClientUtil;
import cn.hutool.core.io.FileUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Map;

/**
 * @author zhengbs
 */
@Service
@Slf4j
public class ResolverResultServiceImpl implements ResolverResultService {

    @Autowired
    private LogMessageProducer logMessageProducer;

    @Value("${resolver.source.file.success.move:true}")
    private boolean successFileMove;

    @Override
    public void success(ResolverMessage resolverMessage, String remoteFileId, Map<String, Object> fileInfoMap, long duration) {
        log.info("<=========> 发送Kafka消息，同步解析成功结果 <=========>");
        logMessageProducer.fileState(resolverMessage.getJobId(),remoteFileId, FileStateEnums.SUCCESS.key(), null, null, duration);
        // 移动文件到成功目录
        handleFile(resolverMessage, fileInfoMap, true);
    }

    @Override
    public void fail(ResolverMessage resolverMessage, String message, String remoteFileId, Map<String, Object> fileInfoMap, long duration, boolean moveFile) {
        log.info("<=========> 发送Kafka消息，同步解析失败结果 <=========>");
        logMessageProducer.fileState(resolverMessage.getJobId(),remoteFileId, FileStateEnums.FAIL.key(), message, null, duration);
        if(moveFile) {
            // 移动文件到失败目录
            handleFile(resolverMessage, fileInfoMap, false);
        }
    }

    /**
     * 移动远程文件，删除本地文件
     */
    private void handleFile(ResolverMessage resolverMessage, Map<String, Object> fileInfoMap, boolean success) {
        if(fileInfoMap.containsKey(LoaderConstant.File_Remote_Path)) {
            ConnectionClient ftpClient = null;
            try {
                String fileRemotePath = (String) fileInfoMap.get(LoaderConstant.File_Remote_Path); // 文件远程地址
                String fileRemoteDir = Paths.get(fileRemotePath).getParent().toString();
                String fileMoveHandler = (String) fileInfoMap.get(LoaderConstant.File_Remote_Handle_After_Resolver);
                if(StringUtils.isBlank(fileMoveHandler)) {
                    fileMoveHandler = FileMoveTypeEnums.MOVE.key();
                }
                String fileMoveHandlerStr = FileMoveTypeEnums.getByKey(fileMoveHandler);
                
                // 获取ftp客户端
                ftpClient = ConnectionClientUtil.getInstance().getConnectionClient(resolverMessage);
                // 移动远程文件移动
                String targetDir = success ? (String) fileInfoMap.get(LoaderConstant.File_Success_Full_Path) :
                        (String) fileInfoMap.get(LoaderConstant.File_Fail_Full_Path);
                // 没有配置转移目录 或者 转移目录与源目录相同，则不转移源文件
                boolean moveSourceFile = StringUtils.isNotBlank(targetDir) && !fileRemoteDir.equals(targetDir);
                if(success && !successFileMove) {
                    moveSourceFile = false;
                }
                log.info("<=========> 配置的{}目录为【{}】,源文件{}{} <=========>", success ? "成功" : "失败", targetDir, moveSourceFile ? "需要":"不需要", fileMoveHandlerStr);
                if(moveSourceFile) {
                    log.info("<=========> 开始{}{}的文件【{}】到【{}】文件夹 <=========>", fileMoveHandlerStr, success ? "成功" : "失败", fileRemotePath, targetDir);
                    handleSourceFile(ftpClient, fileRemotePath, targetDir, fileMoveHandler);
                    log.info("<=========> 结束{}{}的文件【{}】到【{}】文件夹 <=========>", fileMoveHandlerStr, success ? "成功" : "失败", fileRemotePath, targetDir);
                }
                
                if (fileInfoMap.containsKey(LoaderConstant.File_Local_Path)) {
                    // 删除下载后的本地文件
                    String fileLocalPath = (String) fileInfoMap.get(LoaderConstant.File_Local_Path); // 文件本地地址
                    log.info("<=========> 开始删除本地文件【" + fileLocalPath + "】 <=========>");
                    Files.deleteIfExists(Paths.get(fileLocalPath));
                    log.info("<=========> 结束删除本地文件【" + fileLocalPath + "】 <=========>");
                }
                if (fileInfoMap.containsKey(LoaderConstant.File_Local_Prehandle_Path)) {
                    // 删除本地预处理生成的文件
                    String fileLocalPrehandlePath = (String) fileInfoMap.get(LoaderConstant.File_Local_Prehandle_Path); // 预处理文件本地地址
                    log.info("<=========> 开始删除本地预处理文件【" + fileLocalPrehandlePath + "】 <=========>");
                    Files.deleteIfExists(Paths.get(fileLocalPrehandlePath));
                    log.info("<=========> 结束删除本地预处理文件【" + fileLocalPrehandlePath + "】 <=========>");
                }
                // 移动远程关联文件，然后删除本地关联文件
                if (fileInfoMap.containsKey(LoaderConstant.File_Relate_Remote_Paths)) {
                    // 关联文件远程地址 key:远程地址 value:本地地址
                    Map<String, String> fileRelateRemotePaths = (Map<String, String>) fileInfoMap.get(LoaderConstant.File_Relate_Remote_Paths);
                    for (Map.Entry<String, String> entry : fileRelateRemotePaths.entrySet()) {
                        if(moveSourceFile) {
                            log.info("<=========> 开始" + fileMoveHandlerStr + "关联文件【" + entry.getKey() + "】到【" + targetDir + "】文件夹 <=========>");
                            handleSourceFile(ftpClient, entry.getKey(), targetDir, fileMoveHandler);
                            log.info("<=========> 结束" + fileMoveHandlerStr + "关联文件【" + entry.getKey() + "】到【" + targetDir + "】文件夹 <=========>");
                        }
                        log.info("<=========> 开始删除本地文件【" + entry.getValue() + "】 <=========>");
                        Files.deleteIfExists(Paths.get(entry.getValue()));
                        log.info("<=========> 结束删除本地文件【" + entry.getValue() + "】 <=========>");
                    }
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            } finally {
                ConnectionClientUtil.getInstance().releaseConnectionClient(resolverMessage, ftpClient);
            }
        }
    }

    private void handleSourceFile(ConnectionClient ftpClient, String sourcePath, String targetDir, String type) throws Exception {
        if (FileMoveTypeEnums.MOVE.key().equals(type)) {
            moveFile(ftpClient, sourcePath, targetDir);
        } else if (FileMoveTypeEnums.COPY.key().equals(type)) {
            copyFile(ftpClient, sourcePath, targetDir);
        }
    }

    /**
     * 移动文件
     */
    private void moveFile(ConnectionClient ftpClient, String sourcePath, String targetDir) throws Exception {
        String fileName = FileUtil.getName(sourcePath); // 文件名
        if(ftpClient != null) {
            // 移动ftp/sftp服务器上的文件
            ftpClient.move(sourcePath, targetDir, fileName);
        } else {
            // 移动nas服务器上的文件
            Path targetPath = Paths.get(targetDir,fileName);
            if (!Files.exists(targetPath)) {
                Files.createDirectories(targetPath.getParent());
            }
            Files.move(Paths.get(sourcePath), targetPath, StandardCopyOption.REPLACE_EXISTING);
            Files.deleteIfExists(Paths.get(sourcePath));
        }
    }

    /**
     * 拷贝文件
     */
    private void copyFile(ConnectionClient ftpClient, String sourcePath, String targetDir) throws Exception {
        String fileName = FileUtil.getName(sourcePath); // 文件名
        if(ftpClient != null) {
            ftpClient.copy(sourcePath, targetDir, fileName);
        } else {
            // 移动nas服务器上的文件
            Path targetPath = Paths.get(targetDir,fileName);
            if (!Files.exists(targetPath)) {
                Files.createDirectories(targetPath.getParent());
            }
            Files.copy(Paths.get(sourcePath), targetPath, StandardCopyOption.REPLACE_EXISTING);
        }
    }

}
